package com.cobo.lib

import com.cobo.lib.data.LIC_CODE
import com.cobo.lib.data.RAME_SIZE_CODE
import com.cobo.lib.data.ROM_TYPES
import java.io.File
import java.io.RandomAccessFile
import java.nio.ByteBuffer


class RomHeaderStructure(
    // 使用ByteArray存储固定长度数组
    val entry: ByteArray = ByteArray(4),
    val logo: ByteArray = ByteArray(0x30),

    // 字符串处理：使用ByteArray存储，读取时转换为String
    /*
    These bytes contain the title of the game in upper case ASCII. If the title is less than 16 characters long,
    the remaining bytes should be padded with $00s.
    Parts of this area actually have a different meaning on later cartridges,
    reducing the actual title size to 15 ($0134–$0142) or 11 ($0134–$013E) characters; see below.
    * */
    val title: ByteArray = ByteArray(16),

    // 基本数据类型
    var newLicCode: Short = 0,
    var sgbFlag: Byte = 0,
    var type: Byte = 0,
    var romSize: Byte = 0,
    var ramSize: Byte = 0,
    var destCode: Byte = 0,
    var licCode: Byte = 0,
    var version: Byte = 0,
    var checksum: Byte = 0,
    var globalChecksum: Short = 0,
    var x: UShort = 0u
) {
    // 获取标题字符串（从C风格字符串转换）
    val titleString: String
        get() = title.takeWhile { it != 0.toByte() }.toByteArray().toString(Charsets.US_ASCII)

    // 从字节数组解析Header
    companion object {
        fun fromBytes(data: ByteArray, offset: Int = 0): RomHeaderStructure {
            val pos = offset
            return RomHeaderStructure(
                entry = data.copyOfRange(pos, pos + 4),
                logo = data.copyOfRange(pos + 4, pos + 0x34),
                title = data.copyOfRange(pos + 0x34, pos + 0x44),
                newLicCode = (data[pos + 0x44].toUByte().toUInt() shl 8 or
                        data[pos + 0x45].toUByte().toUInt()).toShort(),
                sgbFlag = data[pos + 0x46],
                type = data[pos + 0x47],
                romSize = data[pos + 0x48],
                ramSize = data[pos + 0x49],
                destCode = data[pos + 0x4A],
                licCode = data[pos + 0x4B],
                version = data[pos + 0x4C],
                checksum = data[pos + 0x4D],
                globalChecksum = (data[pos + 0x4E].toUByte().toUInt() shl 8 or
                        data[pos + 0x4F].toUByte().toUInt()).toShort(),
                x = data.copyOfRange(pos + 0x34, pos + 0x4c).fold(0u) { acc, b ->
                    (acc - b.toUShort() - 1u).toUShort()
                }
            )
        }
    }

    // 转换为字节数组（用于写入文件）
    fun toBytes(): ByteArray {
        val data = ByteArray(80) // 结构体总大小
        var pos = 0


        // 复制entry和logo
        entry.copyInto(data, pos)
        pos += 4
        logo.copyInto(data, pos)
        pos += 0x30

        // 复制title
        title.copyInto(data, pos)
        pos += 16

        // 写入其他字段（注意字节序）
        data[pos++] = (newLicCode.toUInt() shr 8).toByte()
        data[pos++] = newLicCode.toUInt().toByte()
        data[pos++] = sgbFlag
        data[pos++] = type
        data[pos++] = romSize
        data[pos++] = ramSize
        data[pos++] = destCode
        data[pos++] = licCode
        data[pos++] = version
        data[pos++] = checksum
        data[pos++] = (globalChecksum.toUInt() shr 8).toByte()
        data[pos] = globalChecksum.toUInt().toByte()

        return data
    }
}

data class RomHeader(val structure: RomHeaderStructure) {
    val title: String get() = structure.titleString
    val romSize: Int get() = 32 * (structure.romSize.toInt() shl 1)
    val ramSize: String get() = RAME_SIZE_CODE[structure.ramSize.toInt()]
    val licCode: String
        get() {
            if (structure.licCode.toUByte() <= 164u) {
                return LIC_CODE[structure.licCode.toUByte().toInt()] ?: "UNKNOWN"
            }
            return "UNKNOWN"
        }
    val type: String
        get() {
            if (structure.type.toUByte() <= 34u) {
                return ROM_TYPES[structure.type.toUByte().toInt()]
            }
            return "UNKNOWN"
        }

    val version: Byte get() = structure.version

    val checkResult: String
        get() {
            return if (structure.x > 0u) "PASSED" else "FAILED"
        }

    fun print() {
        println(
            """
            |Cartridge Loaded:
            |   Title   : $title
            |   Type    : $type
            |   ROMSIZE : ${romSize}KB
            |   RAM Size: $ramSize
            |   LIC CODE: $licCode
            |   ROM VErs" $version
            |   check result: $checkResult
        """.trimMargin("|")
        )
    }
}

data class CartContext(
    var filename: ByteArray = ByteArray(1024),
    var romeSIze: Int = 0,
    var romeData: ByteArray,
    var header: RomHeader
)

fun cartLoad(cartFile: File) {
    println("${cartFile.name} length: ${cartFile.length()}")
    RandomAccessFile(cartFile, "r").use { file ->
        file.channel.use { channel ->
            channel.position(0x100)
            val buffer = ByteBuffer.allocate(0x4f+1)
            val bytesRead = channel.read(buffer)
            println("实际读取字节数: $bytesRead")
            buffer.flip()//切换只读模式
            val header = RomHeaderStructure.fromBytes(buffer.array(), 0)
            RomHeader(header).print()
        }
    }
}


fun main() {

    cartLoad(File("/home/cobo/projects/gameboy/src/main/resources/roms/mem_timing.gb"))
}